package com.example.smart_city_0829.retrofit;

import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;

import com.example.smart_city_0829.SmartCity;
import com.example.smart_city_0829.entity.Base;
import com.example.smart_city_0829.entity.user.Login;
import com.example.smart_city_0829.utils.Constant;
import com.google.gson.Gson;

import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitBuilder {

    private static Api api;
    private static Retrofit.Builder builder;

    private static boolean tokenRefreshed = false;

    private RetrofitBuilder(){

    }

    public static Api getApi() {
        return api;
    }

    public static class Builder{

        public Builder() {
            OkHttpClient client = new OkHttpClient.Builder()
                    .addInterceptor(new Interceptor() {
                        @NonNull
                        @Override
                        public Response intercept(@NonNull Chain chain) throws IOException {
                            final Request request = chain.request().newBuilder()
                                    .addHeader(Constant.HEADER_TOKEN, SmartCity.getSharedPreferences().getString("token", ""))
                                    .build();

                            final Response proceed = chain.proceed(request);

                            final ResponseBody body = proceed.body();

                            final BufferedSource source = body.source();
                            source.request(Long.MAX_VALUE);
                            final Buffer buffer = source.getBuffer();

                            final String responseBody = buffer.clone().readUtf8();

                            final Gson gson = new Gson();
                            final Base baseBean = gson.fromJson(responseBody, Base.class);

                            /**
                             * debug模式下闪退
                             * 2022-09-27 16:59:46.132 9482-9489/com.example.smart_city_0829 A/zygote: art_method.cc:92] Check failed: !ext.IsNull()
                             * 2022-09-27 16:59:46.189 9482-9489/com.example.smart_city_0829 A/zygote: runtime.cc:492] Runtime aborting...
                             * 2022-09-27 16:59:46.189 9482-9489/com.example.smart_city_0829 A/zygote: runtime.cc:492] Aborting thread:
                             * 2022-09-27 16:59:46.189 9482-9489/com.example.smart_city_0829 A/zygote: runtime.cc:492] "JDWP" prio=5 tid=4 Runnable
                             * 2022-09-27 16:59:46.189 9482-9489/com.example.smart_city_0829 A/zygote: runtime.cc:492]   | group="" sCount=0 dsCount=0 flags=0 obj=0x13241018 self=0xa8b0bc00
                             * 2022-09-27 16:59:46.189 9482-9489/com.example.smart_city_0829 A/zygote: runtime.cc:492]   | sysTid=9489 nice=0 cgrp=default sched=0/0 handle=0x9763d970
                             * 2022-09-27 16:59:46.189 9482-9489/com.example.smart_city_0829 A/zygote: runtime.cc:492]   | state=R schedstat=( 110541427 21025042 459 ) utm=8 stm=3 core=3 HZ=100
                             * 2022-09-27 16:59:46.189 9482-9489/com.example.smart_city_0829 A/zygote: runtime.cc:492]   | stack=0x97543000-0x97545000 stackSize=1006KB
                             * 2022-09-27 16:59:46.189 9482-9489/com.example.smart_city_0829 A/zygote: runtime.cc:492]   | held mutexes= "abort lock" "mutator lock"(shared held)
                             */
                            if (baseBean.getCode() == 401 && baseBean.getMsg().contains("认证失败")){
                                synchronized (this){
                                    Log.e("Refresh Token",baseBean.getMsg());

                                    if (tokenRefreshed) {
                                        chain.proceed(chain.request().newBuilder()
                                                .addHeader(Constant.HEADER_TOKEN, SmartCity.getSharedPreferences().getString("token", ""))
                                                .build());
                                    }

                                    tokenRefreshed = false;

                                    final SharedPreferences sharedPreferences = SmartCity.getSharedPreferences();
                                    final String username = sharedPreferences.getString("userName", "");
                                    final String password = sharedPreferences.getString("password", "");

                                    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) return proceed;

                                    final HashMap<String, Object> params = new HashMap<>();
                                    params.put("username",username);
                                    params.put("password",password);
                                    final RequestBody requestBody = RequestBody.create(gson.toJson(params), MediaType.parse("application/json"));
                                    final Login responseBody2 = api.login(requestBody).execute().body();
                                    if (responseBody2.getCode() == 200){
                                        final String token = responseBody2.getToken();
                                        sharedPreferences.edit()
                                                .putString("token",token)
                                                .apply();

                                        final Request finallyRequest = request.newBuilder().addHeader(Constant.HEADER_TOKEN, token)
                                                .build();

                                        proceed.body().close();

                                        tokenRefreshed = true;

                                        return chain.proceed(finallyRequest);

                                    }else {
                                        Log.e("Refresh Token Error",responseBody2.getMsg().toString());
                                    }
                                }
                            }

                            return proceed;
                        }
                    })
                    .build();
            builder = new Retrofit.Builder()
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create());
        }

        public void setBaseUrl(String url){
            builder.baseUrl(url);
        }

        public Api builder(){
            builder.baseUrl(Constant.BASE_URL2);
            api = builder.build().create(Api.class);
            return api;
        }

        public <T> T builder(Class<T> clazz){
            return builder.build().create(clazz);
        }
    }
}
